package websocket.netty.jz;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import websocket.netty.ChannelMap;
import websocket.util.ConfigProperties;

import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * 功能描述: netty服务端处理类
 */
@Slf4j
@ChannelHandler.Sharable
public class JzNettyServerHandler extends ChannelInboundHandlerAdapter {

    public static Map<String, ByteBuf> dataMap = new ConcurrentHashMap<>();
    private final Map<String, String> map = new ConfigProperties().getPropertiesMap("application.yml");

    /**
     * 功能描述: 有客户端连接服务器会触发此函数
     *
     * @param ctx 通道
     * @return void
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        int clientPort = insocket.getPort();
        //获取连接通道唯一标识
        ChannelId channelId = ctx.channel().id();
        //如果map中不包含此连接，就保存连接
        if (ChannelMap.getChannelMap().containsKey(channelId)) {
            log.info("客户端:{},是连接状态，基站连接通道数量:{} ", channelId, ChannelMap.getChannelMap().size());
        } else {
            //保存连接
            ChannelMap.addChannel(channelId, ctx.channel());
            log.info("客户端:{},连接基站的netty服务器[IP:{}-->PORT:{}]", channelId, clientIp, clientPort);
            log.info("基站连接通道数量: {}", ChannelMap.getChannelMap().size());
        }
        ChannelMap.addChannelId(8090, ctx.channel());

    }

    /**
     * 功能描述: 有客户端终止连接服务器会触发此函数
     *
     * @param ctx 通道处理程序上下文
     * @return void
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        InetSocketAddress inSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = inSocket.getAddress().getHostAddress();
        ChannelId channelId = ctx.channel().id();
        //包含此客户端才去删除
        if (ChannelMap.getChannelMap().containsKey(channelId)) {
            //删除连接
            ChannelMap.getChannelMap().remove(channelId);
            log.info("客户端:{},连接8090基站8090的netty服务器[IP:{}-->PORT:{}]", channelId, clientIp, inSocket.getPort());
            log.info("基站连接通道数量: " + ChannelMap.getChannelMap().size());
        }
    }

    /**
     * 功能描述: 有客户端发消息会触发此函数
     *
     * @param ctx 通道处理程序上下文
     * @param msg 客户端发送的消息
     * @return void
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//        log.info("基站8090接收到消息,加载客户端报文,客户端id:{},客户端消息:{} \n", ctx.channel().id(), msg);
        log.info("基站8090接收到消息,加载客户端报文,客户端id:{} \n", ctx.channel().id());
//        if (dataMap.get("data")!=null){
////            log.info("基站数据转发处理完成!");
//            byte[] bytes2 = new byte[dataMap.get("data").readableBytes()];
////            buf.readBytes(bytes2);
//            String needData2 = DigitalTrans.printHexString(bytes2);
//            String horizontalZhenTou = map.get("horizontalZhenTou");
//            String hangXiangZhenTou = map.get("hangXiangZhenTou");
//            ChuanKouService.chuLiChuanKouHangXiangData(needData2, hangXiangZhenTou);
//            ChuanKouService.chuLiChuanKouHorizontalData(needData2, horizontalZhenTou);


//        if (msg instanceof ByteBuf) {
//             输出收到的数据
        ByteBuf buf = null;
        try {
            buf = (ByteBuf) msg;
            sendMsgManyNew(buf);//发送消息
        } catch (Exception e) {//解决了异常数据导致连接中断的问题
            log.info("捕获到数据异常，该条不处理，{}", e.getMessage());
        } finally {
            buf.clear();
        }
//        }
//        ByteBuf buf = null;
//        try {
////            buf = (ByteBuf) msg;
//            sendMsgManyNew(msg);//发送消息
//        } catch (Exception e) {//解决了异常数据导致连接中断的问题
//            log.info("捕获到数据异常，该条不处理，{}", e.getMessage());
//        }
//        finally {
//            buf.clear();
//        }
    }


//    public void sendMsgManyNew(ByteBuf msg) throws Exception {
    public void sendMsgManyNew(ByteBuf msg) throws Exception {
        ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        Channel channel1 = ChannelMap.getChannePortdMap().get(8091);
        if (channel1 == null) {
            log.info("通道:{},不存在", 8091);
        } else {
            channels.add(channel1);
        }

        Channel channel2 = ChannelMap.getChannePortdMap().get(8093);
        if (channel2 == null) {
            log.info("通道:{},不存在", 8093);
        } else {
            channels.add(channel2);
        }

        if (msg == null) {
            log.info("服务端响应空的消息");
            return;
        }
        //向ChannelGroup中的所有客户端发送消息
        channels.writeAndFlush(msg);
        System.out.println("基站分发数据成功");
    }


    public void sendMsgManyString(String msg) throws Exception {
        ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        Channel channel1 = ChannelMap.getChannePortdMap().get(8091);
        if (channel1 == null) {
            log.info("通道:{},不存在", 8091);
        } else {
            channels.add(channel1);
        }

        Channel channel2 = ChannelMap.getChannePortdMap().get(8093);
        if (channel2 == null) {
            log.info("通道:{},不存在", 8093);
        } else {
            channels.add(channel2);
        }

        if (msg == null) {
            log.info("服务端响应空的消息");
            return;
        }
        //向ChannelGroup中的所有客户端发送消息
        channels.writeAndFlush(msg);
    }

    public void sendMsgManyByte(byte[] msg) throws Exception {
        ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        Channel channel1 = ChannelMap.getChannePortdMap().get(8091);
        if (channel1 == null) {
            log.info("通道:{},不存在", 8091);
        } else {
            channels.add(channel1);
        }

        Channel channel2 = ChannelMap.getChannePortdMap().get(8093);
        if (channel2 == null) {
            log.info("通道:{},不存在", 8093);
        } else {
            channels.add(channel2);
        }

        if (msg == null) {
            log.info("服务端响应空的消息");
            return;
        }
        //向ChannelGroup中的所有客户端发送消息
        channels.writeAndFlush(msg);
    }

    public void sendMsgMany(ByteBuf msg) throws Exception {
        ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        Channel channel1 = ChannelMap.getChannePortdMap().get(8091);
        if (channel1 == null) {
            log.info("通道:{},不存在", 8091);
        } else {
            channels.add(channel1);
        }

        Channel channel2 = ChannelMap.getChannePortdMap().get(8093);
        if (channel2 == null) {
            log.info("通道:{},不存在", 8093);
        } else {
            channels.add(channel2);
        }

        if (msg == null) {
            log.info("服务端响应空的消息");
            return;
        }

        byte[] byteArray = new byte[msg.readableBytes()];
        msg.readBytes(byteArray);
        String message = new String(byteArray, Charset.forName("UTF-8"));
        ByteBuf out = Unpooled.copiedBuffer(message.getBytes(Charset.forName("UTF-8")));

        //向ChannelGroup中的所有客户端发送消息
        channels.writeAndFlush(out);
    }


    public void sendMsg(Integer port, ByteBuf msg) throws Exception {
        Channel channel = ChannelMap.getChannePortdMap().get(port);
        if (channel == null) {
            log.info("通道:{},不存在", port);
            return;
        }
        if (msg == null) {
            log.info("服务端响应空的消息");
            return;
        }

        byte[] byteArray = new byte[msg.readableBytes()];
        msg.readBytes(byteArray);
        String message = new String(byteArray, Charset.forName("UTF-8"));

        // 将处理后的数据写回客户端
        ByteBuf out = Unpooled.copiedBuffer(message.getBytes(Charset.forName("UTF-8")));
        //将客户端的信息直接返回写入ctx
        channel.write(out);
        //刷新缓存区
        channel.flush();
    }


    /**
     * 功能描述: 服务端给客户端发送消息
     *
     * @param channelId 连接通道唯一id
     * @param msg       需要发送的消息内容
     */
    public void channelWrite(ChannelId channelId, Object msg) throws Exception {
        Channel channel = ChannelMap.getChannelMap().get(channelId);
        if (channel == null) {
            log.info("通道:{},不存在", channelId);
            return;
        }
        if (msg == null || msg == "") {
            log.info("服务端响应空的消息");
            return;
        }
        //将客户端的信息直接返回写入ctx
        channel.write(msg);
        //刷新缓存区
        channel.flush();
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        String socketString = ctx.channel().remoteAddress().toString();
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                log.info("Client:{},READER_IDLE 读超时", socketString);
                ctx.disconnect();
                Channel channel = ctx.channel();
                ChannelId id = channel.id();
                ChannelMap.removeChannelByName(id);
            } else if (event.state() == IdleState.WRITER_IDLE) {
                log.info("Client:{}, WRITER_IDLE 写超时", socketString);
                ctx.disconnect();
                Channel channel = ctx.channel();
                ChannelId id = channel.id();
                ChannelMap.removeChannelByName(id);
            } else if (event.state() == IdleState.ALL_IDLE) {
                log.info("Client:{},ALL_IDLE 总超时", socketString);
                ctx.disconnect();
                Channel channel = ctx.channel();
                ChannelId id = channel.id();
                ChannelMap.removeChannelByName(id);
            }
        }
    }


    /**
     * 功能描述: 发生异常会触发此函数
     *
     * @param ctx   通道处理程序上下文
     * @param cause 异常
     * @return void
     * @Author keLe
     * @Date 2022/8/26
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        log.info("{}:发生了错误,此连接被关闭。此时连通数量:{}", ctx.channel().id(), ChannelMap.getChannelMap().size());
    }
}
